{
  // 声明一个类
  //
  class Greeter {
    greeting: string;
    constructor(message: string) {
      this.greeting = message;
    }
    greet() {
      return "Hello, " + this.greeting;
    }
  }

  let greeter = new Greeter("world");
  greeter.greet();
}
{
  // 继承
  class Animal {
    name: string;
    constructor(theName: string) {
      this.name = theName;
    }
    move(distanceInMeters: number = 0) {
      console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
  }

  class Snake extends Animal {
    constructor(name: string) {
      super(name);
    }
    move(distanceInMeters = 5) {
      console.log("Slithering...");
      super.move(distanceInMeters);
    }
  }

  class Horse extends Animal {
    constructor(name: string) {
      super(name);
    }
    move(distanceInMeters = 45) {
      console.log("Galloping...");
      super.move(distanceInMeters);
    }
  }

  let sam = new Snake("Sammy the Python");
  let tom: Animal = new Horse("Tommy the Palomino");

  sam.move();
  tom.move(34);
}
{
  // TypeScript 可以使用三种访问修饰符（Access Modifiers），分别是 public、private 和 protected。
  // public 修饰的属性或方法是公有的，可以在任何地方被访问到，默认所有的属性和方法都是 public 的
  {
    class Animal {
      public name: string;
      constructor(theName: string) {
        this.name = theName;
      }
    }
    let a = new Animal("mao");
    // console.log(a.name);
  }
  // private 修饰的属性或方法是私有的，不能在声明它的类的外部访问
  {
    class Animal {
      private name: string;
      constructor(theName: string) {
        this.name = theName;
      }
      public getName(): string {
        return this.name;
      }
    }
    let a = new Animal("mao");
    // 编译报错
    // console.log(a.name);
    // 提供一个 get 方法
    // console.log("getName:", a.getName());
  }
  // protected 修饰的属性或方法是受保护的，它和 private 类似，区别是它在子类中也是允许被访问的
  {
    class Animal {
      protected name: string;
      // 该类只允许被继承，不能用于方法调用
      protected constructor(theName: string) {
        this.name = theName;
      }
      public getName(): string {
        return this.name;
      }
    }

    class Cat extends Animal {
      // 子类中访问
      constructor(name: string) {
        super(name);
      }
    }

    // 编译报错，不能用于方法调用
    // let a = new Animal("mao");
    let c = new Cat("mao");
    // 编译报错
    // console.log(a.name);
    // 提供一个 get 方法
    // console.log("getName:", c.getName());
  }

  {
    // 参数属性
    // 等同于类中定义该属性同时给该属性赋值，使代码更简洁。
    class Animal {
      // public name: string;
      public constructor(public name: string) {
        // this.name = name;
      }
    }
    let a = new Animal("hh");
    // console.log(a.name);
  }

  {
    // readonly 只读属性关键字 只允许出现在属性声明或索引签名或构造函数中。
    class Animal {
      public readonly name: string;
      constructor(name: string) {
        this.name = name;
      }
    }

    let a = new Animal("hh");
    // 编译报错 ：Cannot assign to 'name' because it is a read-only property.
    // a.name = "mm";
  }
}
